package one.stand.controller;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.jmp.base.OrderApi;
import com.jmp.base.dto.*;
import one.stand.advice.ResultEnum;
import one.stand.dto.ConvertUtils;
import one.stand.dto.PageResponse2;
import one.stand.dto.UserDto;
import one.stand.enums.OrderStateEnum;
import one.stand.enums.RefundStateEnum;
import one.stand.mapper.OrderInfoMapperExt;
import one.stand.mapper.OrdersMapperExt;
import one.stand.model.*;
import one.stand.service.GoodsPhotoService;
import one.stand.service.OrdersPayService;
import one.stand.service.OrdersService;
import one.stand.service.user.UserAdminService;
import one.stand.util.AssertUtil;
import one.stand.util.MoneyUtil;
import one.stand.util.SqlUtil;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static one.stand.service.OrdersService.TIMEOUT;

/**
 * 订单信息
 *
 * @author
 */
@RestController
public class OrderController implements OrderApi {

    @Autowired
    private UserAdminService userAdminService;
    @Autowired
    private GoodsPhotoService goodsPhotoService;

    @Autowired
    private OrdersService ordersService;
    @Autowired
    private OrdersPayService ordersPayService;
    @Autowired
    private OrdersMapperExt ordersMapperExt;
    @Autowired
    private OrderInfoMapperExt orderInfoMapperExt;

    @Override
    public ResultModel<OrderSaveVo> save(@RequestBody OrderSaveDto request) {

        List<Integer> orderIds = ordersService.save(request);

        OrderSaveVo vo = OrderSaveVo.builder()
                .orderIds(orderIds)
                .build();
        return ResultModel.success(vo);
    }

    @Override
    public ResultModel cancel(@RequestBody OrderCancelDto request) {
        ordersService.cancel(request.getOrderId());
        return ResultModel.success();
    }

    @Override
    public ResultModel complete(@RequestBody OrderCancelDto request) {
        ordersService.complete(request.getOrderId());
        return ResultModel.success();
    }

    @Override
    public ResultModel<OrderSaveVo> saveAgain(@RequestBody OrderSaveAgainDto request) {
        Orders orders = ordersMapperExt.selectByPrimaryKey(request.getOrderId());
        List<OrderInfo> list = orderInfoMapperExt.selectByOrderId(request.getOrderId());

        List<OrderSaveDto.Goods> goodsList = ConvertUtils.list(list, ordersModel -> {
            return OrderSaveDto.Goods.builder()//商品
                    .specId(ordersModel.getSpecId())
                    .num(ordersModel.getNum())
                    .shopCartId(null)
                    .cardId(null)
                    .forwardId(null)
                    .build();
        });
        OrderSaveDto.Supplier supplier = OrderSaveDto.Supplier.builder()
                .companyId(orders.getCompanyId())
                .totalPrice(null)
                .remark(null)
                .goodsList(goodsList)
                .build();

        List<Integer> orderIds = ordersService.save(OrderSaveDto.builder()
                .checkFlag(false)
                .userId(request.getUserId())
                .addressId(null)
                .total(null)
                .totalPrice(null)
                .supplierList(Lists.newArrayList(supplier))
                .build());

        OrderSaveVo vo = OrderSaveVo.builder()
                .orderIds(orderIds)
                .build();
        return ResultModel.success(vo);
    }

    @Override
    public ResultModel<OrderPayWxAppVo> payWxApp(@RequestBody OrderPayWxAppDto request) {

        OrderPayWxAppVo vo = ordersPayService.payWxApp(request.getOrderIds(), request.getOptUserId());
        return ResultModel.success(vo);
    }

    @Override
    public ResultModel payWxAppBack(@RequestBody OrderPayWxAppBackDto request) {

        ordersPayService.payWxAppBack(request.getNotifyData());

        return ResultModel.success();
    }

    @Override
    public ResultModel<OrderPayWxJsapiVo> payWxJsapi(@RequestBody OrderPayWxJsapiDto request) {

        Map<String, String> map = ordersPayService.payWxJsapi(request.getOrderId(), request.getAddressId(), request.getRemark(), request.getOptUserId());

        OrderPayWxJsapiVo vo = OrderPayWxJsapiVo.builder()
                .payInfo(map)
                .build();
        return ResultModel.success(vo);
    }

    @Override
    public ResultModel payWxJsapiBack(@RequestBody OrderPayWxAppBackDto request) {

        ordersPayService.payWxJsapiBack(request.getNotifyData());

        return ResultModel.success();
    }

    @Override
    public ResultModel<OrderPayWxAlipayVo> payAlipay(@RequestBody OrderPayWxAlipayDto request) {

        String orderInfo = ordersPayService.payAlipay(request.getOrderIds(), request.getOptUserId());

        OrderPayWxAlipayVo vo = OrderPayWxAlipayVo.builder()
                .orderInfo(orderInfo)
                .build();
        return ResultModel.success(vo);
    }

    @Override
    public ResultModel payAlipayBack(@RequestBody OrderPayWxAlipayBackDto request) {

        ordersPayService.payAlipayBack(request.getParams());

        return ResultModel.success();
    }

    @Override
    public ResultModel send(@RequestBody OrderSendRequest request) {
        ordersService.send(request.getOrderId(), request.getDeliveryCompany(), request.getDeliveryNo());
        return ResultModel.success();
    }

    @Override
    public ResultModel<OrderListPcResponse> listPc(@RequestBody OrderListPcRequest request) {
        AssertUtil.nonNull(request.getCompanyId(), ResultEnum.PARAM_CHECK);

        OrdersModel model = new OrdersModel();
        model.setCompanyId(request.getCompanyId());
        model.setOrderState(request.getOrderState());
        model.setCreateTimes(StringUtils.defaultIfBlank(request.getCreateTimes(), null));
        if (request.getPageNum() >= 0) {
            PageHelper.startPage(request.getPageNum(), request.getPageSize());
        }
        List<Orders> orders = ordersMapperExt.selectList(null, request.getCompanyId(), request.getOrderState(), null, StringUtils.defaultIfBlank(request.getCreateTimes(), null));

        PageResponse2<OrderListPcResponse.Order> pageInfo = ConvertUtils.page2(orders, obj -> {
            List<OrderInfo> list = orderInfoMapperExt.selectByOrderId(obj.getOrdersId());
            OrderListPcResponse.Order order = OrderListPcResponse.Order.builder()
                    .ordersId(obj.getOrdersId())
                    .ordersNo(obj.getOrdersNo())
                    .address(obj.getAddressDetail())
                    .createTime(obj.getCreateTime())
                    .orderState(obj.getOrderState())
                    .refundState(obj.getRefundState())
                    .orderPrice(MoneyUtil.getMoney(obj.getOrderPrice()))
                    .remark(obj.getRemark())
                    .deliveryCompany(obj.getDeliveryCompany())
                    .deliveryNo(obj.getDeliveryNo())
                    .goodsName(list.stream().map(OrderInfo::getGoodsName).collect(Collectors.joining()))
                    .specAttribute(list.stream().map(OrderInfo::getSpecName).collect(Collectors.joining()))
                    .build();
            UserDto user = userAdminService.get(obj.getUserId());
            order.setNickeName(user.getName());
            order.setPhone(user.getPhone());
            return order;
        });

        OrderListPcResponse response = OrderListPcResponse.builder()
                .pageInfo(pageInfo)
                .build();
        return ResultModel.success(response);
    }

    @Override
    public ResultModel<OrderListVo> list(@RequestBody OrderListDto request) {

        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<Orders> orders = ordersMapperExt.selectList(request.getUserId(), request.getCompanyId(), request.getStatus(), SqlUtil.like(request.getKeyword()), null);
        PageResponse2<OrderListVo.Order> orderPageResponse2 = ConvertUtils.page2(orders, order -> {

            List<OrderInfo> list = orderInfoMapperExt.selectByOrderId(order.getOrdersId());
            return OrderListVo.Order.builder()
                    .orderId(order.getOrdersId())
                    .orderPrice(MoneyUtil.getMoney(order.getOrderPrice()))
                    .companyId(order.getCompanyId())
                    .userId(order.getUserId())
                    .orderState(order.getOrderState())
                    .refundState(order.getRefundState())
                    .refundRemark(order.getRefundRemark())

                    .cancelFlag(BooleanUtils.toInteger(order.getOrderState().equals(OrderStateEnum.WAIT_PAYMENT.getCode())))
                    .payFlag(BooleanUtils.toInteger(order.getOrderState().equals(OrderStateEnum.WAIT_PAYMENT.getCode())))
                    .refundFlag(BooleanUtils.toInteger(order.getRefundState().equals(RefundStateEnum.NO_REFUND.getCode()) &&
                            (order.getOrderState().equals(OrderStateEnum.WAIT_DELIVER.getCode()) || order.getOrderState().equals(OrderStateEnum.WAIT_RECEIVING.getCode()))))
                    .refundCancelFlag(BooleanUtils.toInteger(order.getRefundState().equals(RefundStateEnum.REFUND_APPLY.getCode())))
                    .remindSendFlag(BooleanUtils.toInteger(order.getRefundState().equals(RefundStateEnum.NO_REFUND.getCode())
                            && order.getOrderState().equals(OrderStateEnum.WAIT_DELIVER.getCode())))
                    .sendFlag(BooleanUtils.toInteger(order.getRefundState().equals(RefundStateEnum.NO_REFUND.getCode())
                            && order.getOrderState().equals(OrderStateEnum.WAIT_DELIVER.getCode())))
                    .completeFlag(BooleanUtils.toInteger(order.getRefundState().equals(RefundStateEnum.NO_REFUND.getCode())
                            && order.getOrderState().equals(OrderStateEnum.WAIT_RECEIVING.getCode())))

                    .goodsList(ConvertUtils.list(list, orderInfo -> {
                        return OrderListVo.Goods.builder()
                                .goodsId(orderInfo.getGoodsId())
                                .goodsName(orderInfo.getGoodsName())
                                .goodsPhoto(goodsPhotoService.getPath(orderInfo.getGoodsId()))
                                .skuName(orderInfo.getSpecName())
                                .skuNum(orderInfo.getNum())
                                .price(MoneyUtil.getMoney(orderInfo.getPrice()))
                                .cardId(orderInfo.getCardId())
                                .build();
                    }))
                    .build();
        });

        OrderListVo vo = OrderListVo.builder()
                .orderPage(orderPageResponse2)
                .build();
        return ResultModel.success(vo);
    }

    @Override
    public ResultModel<OrderDetailVo> detail(@RequestBody OrderDetailDto request) {

        Orders orders = ordersMapperExt.selectByPrimaryKey(request.getOrderId());

        List<OrderInfo> list = orderInfoMapperExt.selectByOrderId(request.getOrderId());

        Long payTimeLeft = null;
        if (OrderStateEnum.WAIT_PAYMENT.getCode().equals(orders.getOrderState())) {
            Date payLimitDate = DateUtil.offset(orders.getCreateTime(), DateField.MINUTE, TIMEOUT);
            payTimeLeft = DateUtil.between(new Date(), payLimitDate, DateUnit.SECOND);
        }

        OrderDetailVo vo = OrderDetailVo.builder()
                .orderId(orders.getOrdersId())
                .orderNo(orders.getOrdersNo())
                .tradeNo(orders.getTradeNo())
                .orderPrice(MoneyUtil.getMoney(orders.getOrderPrice()))
                .userId(orders.getUserId())
                .companyId(orders.getCompanyId())
                .orderState(orders.getOrderState())
                .orderRemark(orders.getRemark())
                .orderCreateTime(orders.getCreateTime().getTime())
                .payType(orders.getPayType())
                .payPrice(MoneyUtil.getMoney(orders.getPayPrice()))
                .orderPayTime(Objects.nonNull(orders.getPayTime()) ? orders.getPayTime().getTime() : null)
                .deliveryType(orders.getDeliveryType())
                .deliveryCompany(orders.getDeliveryCompany())
                .deliveryNo(orders.getDeliveryNo())
                .refundState(orders.getRefundState())
                .refundRemark(orders.getRefundRemark())
                .addressId(orders.getAddressId())
                .addressName(orders.getAddressName())
                .addressPhone(orders.getAddressPhone())
                .addressDetail(orders.getAddressDetail())

                .goodsList(ConvertUtils.list(list, orderInfo -> {
                    return OrderDetailVo.Goods.builder()
                            .goodsId(orderInfo.getGoodsId())
                            .goodsName(orderInfo.getGoodsName())
                            .goodsPhoto(goodsPhotoService.getPath(orderInfo.getGoodsId()))
                            .skuName(orderInfo.getSpecName())
                            .skuNum(orderInfo.getNum())
                            .price(MoneyUtil.getMoney(orderInfo.getPrice()))
                            .cardId(orderInfo.getCardId())
                            .build();
                }))

                .payTimeLeft(payTimeLeft)

                .build();
        return ResultModel.success(vo);
    }

    @Override
    public ResultModel remindSend(@RequestBody OrderRemindSendDto request) {

        ordersService.remindSend(request.getOrderId());

        return ResultModel.success();
    }

    @Override
    public ResultModel refundApply(@RequestBody OrderRefundApplyDto request) {

        ordersService.refundApply(request.getOrderId(), request.getRefundRemark());

        return ResultModel.success();
    }

    @Override
    public ResultModel refundCancel(@RequestBody OrderRefundCancelDto request) {

        ordersService.refundApplyCancel(request.getOrderId());

        return ResultModel.success();
    }

    @Override
    public ResultModel timeout(@RequestBody OrderTimeoutDto request) {

        ordersService.timeout();

        return ResultModel.success();
    }

    @Override
    public ResultModel<OrderCountVo> count(@RequestBody OrderCountDto request) {
        List<OrderCountVo.StateVo> result = ordersMapperExt.getOrderListCount(request.getUserId());
        OrderCountVo vo = OrderCountVo.builder()
                .result(result)
                .build();
        return ResultModel.success(vo);
    }
}
